package screen_calibration;

import java.awt.Point;

/*************************************************
 * File:	Diagram.java
 * Description:	Computes chromaticity diagram
 *
 * Author: Gene Vishnevsky  Oct. 15, 1997
*************************************************/

/**
* This class computes the chromaticity diagram data.
*/
public class Diagram {

	final float XR=0.64f, YR=0.33f, XG=0.29f, YG=0.60f,
		XB=0.15f, YB=0.06f, XW=0.3127f, YW=0.3291f,
		GAM=0.8f;

	final float ZR=1.0f-(XR+YR),
		ZG=1.0f-(XG+YG),
		ZB=1.0f-(XB+YB),
		ZW=1.0f-(XW+YW);

	int M = 300, N = 300;
	
	public short range[][];

	/**
	* Chromaticity values
	*/
	public ChromaticityData data = new ChromaticityData();

	public float R, G, B;


	/**
	* This constructor simply initialized the size variables.
	* @param m width of the diagram in pixels
	* @param n height of the diagram in pixels
	*/
	public Diagram( int m, int n ) {
		M = m;
		N = n;
		range = new short[m][2];
	}

	/**
	* Computes the array of pixels representing the diagram.
	* @param icv[][] preallocated array to place computed pixels.
	*/
	public void Compute( int icv[][] ) {
		int i, j, ii, jj, i1, i2, j1, j2 = 0, itest, jtest;
		float s, s1, s2, t1, t2, slope, RMAX;


		//	Draw tongue outline and init range array
		for( i = 0; i < M; i++ ) {
			range[i][0] = 10000;		// min value
			range[i][1] = -10000;		// max value
			for( j = 0; j < N; j++ )
				icv[i][j] = 0;
		}
	
		for( j = 0; j < 81; j++ ) {				//DO J=1,81
			s1 = (float)M * data.wxy[j].x;
			s2 = (float)M * data.wxy[j+1].x;
			t1 = (float)N * (1.f - data.wxy[j].y);
			t2 = (float)N * (1.f - data.wxy[j+1].y);
			slope = (t2-t1) / (s2-s1);
			i1 = (int)(s1+0.5f);
			i2 = (int)(s2+0.5f);
			if( i1 < i2 ) {
				for( ii = i1; ii <= i2; ii++ ) {
					s = (float)ii;
					j1 = j2;
					j2=(int)(t1+slope*(s-s1)  +0.5f );
					if( j1 != 0 && j2 != 0 ) {
						if( j1 < j2 ) {
							for( jj = j1; jj <= j2; jj++ ) {
								icv[ii-1][jj-1] = toRGB( 1, 1, 1 ); //was 255,1,1
								UpdateRange( ii, jj );
							}
						}
						else {
							for( jj = j2; jj <= j1; jj++ ) {
								icv[ii-1][jj-1] = toRGB( 1, 1, 1 ); // was 1,255,1
								UpdateRange( ii, jj );
							}
						}
					}
				}
			}
			else {
				for( ii = i1; ii > i2; ii-- ) {
					s = (float)ii;
					j1 = j2;
					j2=(int)(t1+slope*(s-s1) +0.5f );
					if( j1 != 0 && j2 != 0 ) {
						if( j1 < j2 ) {
							for( jj = j1; jj <= j2; jj++ ) {
								icv[ii-1][jj-1] = toRGB( 1, 1, 1 ); //was 200,200,0
								UpdateRange( ii, jj );
							}
						}
						else {
							for( jj = j2; jj <= j1; jj++ ) {
								icv[ii-1][jj-1] = toRGB( 1, 1, 1 ); //was 1, 1, 255
								UpdateRange( ii, jj );
							}
						}
					}
				}
			}
		} //for( j=0..81 )

		// Calculate RGB Values for x and y coordinates
	
		for( j = 1; j <= N; j++ ) {
			jtest = 0;
			for( i = 1; i <= M; i++ ) {
				if( (icv[i-1][j-1] & (255<<16)) == (1<<16) &&
					 (icv[i][j-1] & (255<<16)) == 0 )
					jtest++;
			}
			if( jtest == 2 ) {
				itest = 0;
				for( i = 1; i <= M; i++ ) {
					if( (icv[i-1][j-1] & (255<<16)) == (1<<16) &&
						 (icv[i][j-1] & (255<<16)) == 0 )
						itest++;
					if( itest == 1 ) {
						float xc, yc, zc;
						xc = (float)i / (float)M;
						yc = 1.f - (float)j / (float)N;
						zc = 1.f - (xc+yc);
						xyz2rgb( xc, yc, zc );
						RMAX = 0.0000000001f;
						if( R > RMAX ) RMAX = R;
						if( G > RMAX ) RMAX = G;
						if( B > RMAX ) RMAX = B;
						int ired, igreen, iblue;
						ired = (int)( 255. * Math.pow( R/RMAX, GAM ) );
						igreen = (int)( 255. * Math.pow( G/RMAX, GAM ) );
						iblue = (int)( 255. * Math.pow( B/RMAX, GAM ) );
						icv[i-1][j-1] = toRGB( ired, igreen, iblue );
					}
				}
			}
		}
	}

	public int toRGB( int red, int green, int blue ) {
		return ( (255<<24) | (red<<16) | (green<<8) | blue );
	}


	public void UpdateRange( int i, int j ) {
		// The values passed are 1 bigger, so decrement
		i--;
		j--;
		if( range[i][0] > j )
			range[i][0] = (short)j;		// new min
		if( range[i][1] < j )
			range[i][1] = (short)j;		// new max
	}

	/**
	* Checks if a point belongs to the chromaticity diagram.
	* @param i the absciss pixel number [0,m]
	* @param j the ordinate pixel number [0,n]
	* @return true if pixel belongs to the chromaticity diagram;
	* false otherwise.
	*/
	public boolean isInRange( int i, int j ) {
		if( i < 0 || i >= M )
			return false;
        if( j < range[i][0] || j > range[i][1] ){

            System.out.println("j= " + j + "; range[i][0]= " + range[i][0] + "; range[i][1]= " + range[i][1]);
            return false;
        }
		
		return true;
	}
	
		public void xyz2rgb( float xc, float yc, float zc ) {

		R=(-XG*yc*ZB+xc*YG*ZB+XG*YB*zc-XB*YG*zc-xc*YB*ZG+XB*yc*ZG)/
			( XR*YG*ZB-XG*YR*ZB-XR*YB*ZG+XB*YR*ZG+XG*YB*ZR-XB*YG*ZR);
		G=( XR*yc*ZB-xc*YR*ZB-XR*YB*zc+XB*YR*zc+xc*YB*ZR-XB*yc*ZR)/
			( XR*YG*ZB-XG*YR*ZB-XR*YB*ZG+XB*YR*ZG+XG*YB*ZR-XB*YG*ZR);
		B=( XR*YG*zc-XG*YR*zc-XR*yc*ZG+xc*YR*ZG+XG*yc*ZR-xc*YG*ZR)/
			( XR*YG*ZB-XG*YR*ZB-XR*YB*ZG+XB*YR*ZG+XG*YB*ZR-XB*YG*ZR);

		if( R < 0 ) R=0.f;
		if( G < 0 ) G=0.f;
		if( B < 0 ) B=0.f;
		if( R > 1 ) R=1.f;
		if( G > 1 ) G=1.f;
		if( B > 1 ) B=1.f;
	}


}
